`cargo metadata` works with workspaces
authorAleksey Kladov <aleksey.kladov@gmail.com>
Sun, 28 Aug 2016 12:10:27 +0000 (15:10 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Sun, 28 Aug 2016 12:10:27 +0000 (15:10 +0300)
src/cargo/ops/cargo_output_metadata.rs
src/cargo/ops/resolve.rs
tests/metadata.rs

index 658a588afd5076575d0b67760fa1e0aa853d7cf9..5178dbc8eec59c3a23c82d35d0e7c23b6e1dacb8 100644 (file)
@@ -33,7 +33,8 @@ pub fn output_metadata(ws: &Workspace,
 fn metadata_no_deps(ws: &Workspace,
                     _opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
     Ok(ExportInfo {
-        packages: vec![try!(ws.current()).clone()],
+        packages: ws.members().cloned().collect(),
+        workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
         resolve: None,
         version: VERSION,
     })
@@ -53,7 +54,11 @@ fn metadata_full(ws: &Workspace,
 
     Ok(ExportInfo {
         packages: packages,
-        resolve: Some(MetadataResolve(resolve, try!(ws.current()).package_id().clone())),
+        workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(),
+        resolve: Some(MetadataResolve{
+            resolve: resolve,
+            root: ws.current_opt().map(|pkg| pkg.package_id().clone()),
+        }),
         version: VERSION,
     })
 }
@@ -61,6 +66,7 @@ fn metadata_full(ws: &Workspace,
 #[derive(RustcEncodable)]
 pub struct ExportInfo {
     packages: Vec<Package>,
+    workspace_members: Vec<PackageId>,
     resolve: Option<MetadataResolve>,
     version: u32,
 }
@@ -68,13 +74,16 @@ pub struct ExportInfo {
 /// Newtype wrapper to provide a custom `Encodable` implementation.
 /// The one from lockfile does not fit because it uses a non-standard
 /// format for `PackageId`s
-struct MetadataResolve(Resolve, PackageId);
+struct MetadataResolve{
+    resolve: Resolve,
+    root: Option<PackageId>,
+}
 
 impl Encodable for MetadataResolve {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         #[derive(RustcEncodable)]
         struct EncodableResolve<'a> {
-            root: &'a PackageId,
+            root: Option<&'a PackageId>,
             nodes: Vec<Node<'a>>,
         }
 
@@ -84,14 +93,12 @@ impl Encodable for MetadataResolve {
             dependencies: Vec<&'a PackageId>,
         }
 
-        let resolve = &self.0;
-        let root = &self.1;
         let encodable = EncodableResolve {
-            root: root,
-            nodes: resolve.iter().map(|id| {
+            root: self.root.as_ref(),
+            nodes: self.resolve.iter().map(|id| {
                 Node {
                     id: id,
-                    dependencies: resolve.deps(id).collect(),
+                    dependencies: self.resolve.deps(id).collect(),
                 }
             }).collect(),
         };
index eb5713294845da5543cf8b187f453923467a4857..7ab3d1b4c12dc8fce63ac50615c6788a7ced2594 100644 (file)
@@ -60,21 +60,18 @@ pub fn resolve_with_previous<'a>(registry: &mut PackageRegistry,
                                           .clone()]));
 
         // If we're resolving everything then we include all members of the
-        // workspace. If we want a specific set of requirements then we only
-        // resolve the main crate as it's the only one we're compiling. This
+        // workspace. If we want a specific set of requirements and we're
+        // compiling only a single workspace crate then resolve only it. This
         // case should only happen after we have a previous resolution, however,
         // so assert that the previous exists.
-        let method = match method {
-            Method::Everything => Method::Everything,
-            Method::Required { .. } => {
-                assert!(previous.is_some());
-                if member.package_id() == try!(ws.current()).package_id() {
-                    method
-                } else {
-                    continue
+        if let Method::Required { .. } = method {
+            assert!(previous.is_some());
+            if let Some(current) = ws.current_opt() {
+                if member.package_id() != current.package_id() {
+                    continue;
                 }
             }
-        };
+        }
 
         // If we don't have a previous instance of resolve then we just need to
         // resolve our entire summary (method should be Everything) and we just
index 4d5df0f414fd4430501ac5c70894b875dd16c116..2f2c21056e5ee67c99ba2ebec3b0882a5c9f7daf 100644 (file)
@@ -3,7 +3,7 @@ extern crate hamcrest;
 
 use hamcrest::assert_that;
 use cargotest::support::registry::Package;
-use cargotest::support::{project, execs, basic_bin_manifest, main_file};
+use cargotest::support::{project, execs, basic_bin_manifest, basic_lib_manifest, main_file};
 
 #[test]
 fn cargo_metadata_simple() {
@@ -32,6 +32,7 @@ fn cargo_metadata_simple() {
                 "manifest_path": "[..]Cargo.toml"
             }
         ],
+        "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
         "resolve": {
             "nodes": [
                 {
@@ -149,6 +150,7 @@ fn cargo_metadata_with_deps_and_version() {
                 "version": "0.5.0"
             }
         ],
+        "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
         "resolve": {
             "nodes": [
                 {
@@ -174,6 +176,128 @@ fn cargo_metadata_with_deps_and_version() {
     }"#));
 }
 
+#[test]
+fn workspace_metadata() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [workspace]
+            members = ["bar", "baz"]
+        "#)
+        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
+        .file("bar/src/lib.rs", "")
+        .file("baz/Cargo.toml", &basic_lib_manifest("baz"))
+        .file("baz/src/lib.rs", "");
+    p.build();
+
+    assert_that(p.cargo_process("metadata"), execs().with_status(0).with_json(r#"
+    {
+        "packages": [
+            {
+                "name": "bar",
+                "version": "0.5.0",
+                "id": "bar[..]",
+                "source": null,
+                "dependencies": [],
+                "targets": [
+                    {
+                        "kind": [ "lib" ],
+                        "name": "bar",
+                        "src_path": "[..]bar[..]src[..]lib.rs"
+                    }
+                ],
+                "features": {},
+                "manifest_path": "[..]bar[..]Cargo.toml"
+            },
+            {
+                "name": "baz",
+                "version": "0.5.0",
+                "id": "baz[..]",
+                "source": null,
+                "dependencies": [],
+                "targets": [
+                    {
+                        "kind": [ "lib" ],
+                        "name": "baz",
+                        "src_path": "[..]baz[..]src[..]lib.rs"
+                    }
+                ],
+                "features": {},
+                "manifest_path": "[..]baz[..]Cargo.toml"
+            }
+        ],
+        "workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
+        "resolve": {
+            "nodes": [
+                {
+                    "dependencies": [],
+                    "id": "baz 0.5.0 (path+file:[..]baz)"
+                },
+                {
+                    "dependencies": [],
+                    "id": "bar 0.5.0 (path+file:[..]bar)"
+                }
+            ],
+            "root": null
+        },
+        "version": 1
+    }"#))
+}
+
+#[test]
+fn workspace_metadata_no_deps() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [workspace]
+            members = ["bar", "baz"]
+        "#)
+        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
+        .file("bar/src/lib.rs", "")
+        .file("baz/Cargo.toml", &basic_lib_manifest("baz"))
+        .file("baz/src/lib.rs", "");
+    p.build();
+
+    assert_that(p.cargo_process("metadata").arg("--no-deps"), execs().with_status(0).with_json(r#"
+    {
+        "packages": [
+            {
+                "name": "bar",
+                "version": "0.5.0",
+                "id": "bar[..]",
+                "source": null,
+                "dependencies": [],
+                "targets": [
+                    {
+                        "kind": [ "lib" ],
+                        "name": "bar",
+                        "src_path": "[..]bar[..]src[..]lib.rs"
+                    }
+                ],
+                "features": {},
+                "manifest_path": "[..]bar[..]Cargo.toml"
+            },
+            {
+                "name": "baz",
+                "version": "0.5.0",
+                "id": "baz[..]",
+                "source": null,
+                "dependencies": [],
+                "targets": [
+                    {
+                        "kind": [ "lib" ],
+                        "name": "baz",
+                        "src_path": "[..]baz[..]src[..]lib.rs"
+                    }
+                ],
+                "features": {},
+                "manifest_path": "[..]baz[..]Cargo.toml"
+            }
+        ],
+        "workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
+        "resolve": null,
+        "version": 1
+    }"#))
+}
+
 #[test]
 fn cargo_metadata_with_invalid_manifest() {
     let p = project("foo")
@@ -204,6 +328,7 @@ const MANIFEST_OUTPUT: &'static str=
         "features":{},
         "manifest_path":"[..]Cargo.toml"
     }],
+    "workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ],
     "resolve": null,
     "version": 1
 }"#;